//  MainFrameViewController.m
//  Moonlight
//
//  Created by Diego Waxemberg on 1/17/14.
//  Copyright (c) 2014 Moonlight Stream. All rights reserved.
//

@import ImageIO;

#import "MainFrameViewController.h"
#import "CryptoManager.h"
#import "HttpManager.h"
#import "Connection.h"
#import "StreamManager.h"
#import "Utils.h"
#import "UIComputerView.h"
#import "UIAppView.h"
#import "DataManager.h"
#import "TemporarySettings.h"
#import "WakeOnLanManager.h"
#import "AppListResponse.h"
#import "ServerInfoResponse.h"
#import "StreamFrameViewController.h"
#import "ComputerScrollView.h"
#import "TemporaryApp.h"
#import "IdManager.h"
#import "ConnectionHelper.h"
#import <VideoToolbox/VideoToolbox.h>
#import <SVProgressHUD/SVProgressHUD.h>
#include <Limelight.h>
#include "PortManager.h"

@interface MainFrameViewController () <UICollectionViewDelegate, UICollectionViewDataSource>

@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) ComputerScrollView *hostScrollView;
@property (nonatomic, strong) DiscoveryManager *discoveryMgr;
@property (nonatomic, strong) AppAssetManager *appManager;
@property (nonatomic, strong) UIAlertController *pairAlert;
@property (nonatomic, strong) NSMutableSet <TemporaryHost *>*hostList;
@property (nonatomic, copy) NSString *ipAddress; // 当前需要连接的设备ipAddress
@property (nonatomic, copy) NSString *vnName; // 当前需要连接设备name
@property (nonatomic, assign) BOOL isSunshine;
@end

@implementation MainFrameViewController {
    NSOperationQueue* _opQueue;
    TemporaryHost* _selectedHost;
    BOOL _showHiddenApps;
    NSString* _uniqueId;
    NSData* _clientCert;
    StreamConfiguration* _streamConfig;
    NSArray* _sortedAppList;
    NSCache* _boxArtCache;
    bool _background;
}

/// 开始配对
- (void)startPairing:(NSString *)PIN {
    NSLog(@"开始匹配PIN = %@", PIN);
    if (self.deleagte && [self.deleagte respondsToSelector:@selector(readyPin:)]) {
        [self.deleagte readyPin:PIN];
    }
}

//MARK: - 开始启动对应的电脑
- (void)startPC {
    [self setOther];
    
    [self.hostList enumerateObjectsUsingBlock:^(TemporaryHost * _Nonnull obj, BOOL * _Nonnull stop) {
        if ([obj isKindOfClass:TemporaryHost.class]) {
            if ([obj.activeAddress isEqualToString:self.ipAddress]) {
                // 找到了电脑，直接进行点击操作
                [self hostClicked:obj view:[UIComputerView new]];
                *stop = YES;
            }
        }
    }];
}

//MARK: - PairCallback

// 配对失败
- (void)displayPairingFailureDialog:(NSString *)message {
    if (self.deleagte && [self.deleagte respondsToSelector:@selector(pairFailed:)]) {
        [self.deleagte pairFailed:message];
    }
    
    [self.discoveryMgr startDiscovery];
    [self showHostSelectionView];
}

// 配对失败的处理
- (void)pairFailed:(NSString *)message {
    if (self.deleagte && [self.deleagte respondsToSelector:@selector(pairFailed:)]) {
        [self.deleagte pairFailed:message];
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.pairAlert != nil) {
            [self.pairAlert dismissViewControllerAnimated:YES completion:^{
                [self displayPairingFailureDialog:message];
            }];
            self.pairAlert = nil;
        }
    });
}

// 配对成功
- (void)pairSuccessful:(NSData*)serverCert {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Store the cert from pairing with the host
        self->_selectedHost.serverCert = serverCert;
        
        [self.pairAlert dismissViewControllerAnimated:YES completion:nil];
        self.pairAlert = nil;
        
        [self.discoveryMgr startDiscovery];
        [self alreadyPaired];
    });
}

// 配对成功
- (void)alreadyPaired {
    BOOL usingCachedAppList = false;
    
    // 捕获这里的主机，因为它可以改变，一旦我们退出主线程
    TemporaryHost* host = _selectedHost;
    if (host == nil) {
        return;
    }
    
    if ([host.appList count] > 0) {
        usingCachedAppList = true;
        dispatch_async(dispatch_get_main_queue(), ^{
            if (host != self->_selectedHost) {
                return;
            }
            
            [self updateAppsForHost:host];
        });
    }
    
    Log(LOG_I, @"使用缓存的应用列表: %d", usingCachedAppList);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        // 在处理应用程序查询时免除该主机的发现
        [self.discoveryMgr pauseDiscoveryForHost:host];
        
        AppListResponse *appListResp = [ConnectionHelper getAppListForHost:host];
        
        [self.discoveryMgr resumeDiscoveryForHost:host];
        
        if (![appListResp isStatusOk] || [appListResp getAppList] == nil) {
            Log(LOG_W, @"Failed to get applist: %@", appListResp.statusMessage);
            dispatch_async(dispatch_get_main_queue(), ^{
                if (host != self->_selectedHost) {
                    return;
                }
                
                UIAlertController* applistAlert = [UIAlertController alertControllerWithTitle:@"连接中断"
                                                                                      message:appListResp.statusMessage
                                                                               preferredStyle:UIAlertControllerStyleAlert];
                [Utils addHelpOptionToDialog:applistAlert];
                [applistAlert addAction:[UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil]];
                [self showHostSelectionView];
                [[self activeViewController] presentViewController:applistAlert animated:YES completion:nil];
                host.state = StateOffline;
            });
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self updateApplist:[appListResp getAppList] forHost:host];
                
                if (host != self->_selectedHost) {
                    return;
                }
                
                [self updateAppsForHost:host];
                [self.appManager stopRetrieving];
                [self.appManager retrieveAssetsFromHost:host];
            });
        }
    });
}

- (void)updateAppEntry:(TemporaryApp*)app forHost:(TemporaryHost*)host {
    DataManager* database = [[DataManager alloc] init];
    NSMutableSet* newHostAppList = [NSMutableSet setWithSet:host.appList];
    
    for (TemporaryApp* savedApp in newHostAppList) {
        if ([app.id isEqualToString:savedApp.id]) {
            savedApp.name = app.name;
            savedApp.hdrSupported = app.hdrSupported;
            savedApp.hidden = app.hidden;
            
            host.appList = newHostAppList;
            
            [database updateAppsForExistingHost:host];
            return;
        }
    }
}

- (void)updateApplist:(NSSet*)newList forHost:(TemporaryHost*)host {
    DataManager* database = [[DataManager alloc] init];
    NSMutableSet* newHostAppList = [NSMutableSet setWithSet:host.appList];
    
    for (TemporaryApp* app in newList) {
        BOOL appAlreadyInList = NO;
        for (TemporaryApp* savedApp in newHostAppList) {
            if ([app.id isEqualToString:savedApp.id]) {
                savedApp.name = app.name;
                savedApp.hdrSupported = app.hdrSupported;
                appAlreadyInList = YES;
                break;
            }
        }
        if (!appAlreadyInList) {
            app.host = host;
            [newHostAppList addObject:app];
        }
    }
    
    BOOL appWasRemoved;
    do {
        appWasRemoved = NO;
        
        for (TemporaryApp* app in newHostAppList) {
            appWasRemoved = YES;
            for (TemporaryApp* mergedApp in newList) {
                if ([mergedApp.id isEqualToString:app.id]) {
                    appWasRemoved = NO;
                    break;
                }
            }
            if (appWasRemoved) {
                // 删除应用程序会改变我们正在迭代的列表(这是不合法的)。
                [newHostAppList removeObject:app];
                
                // 从数据库中删除应用程序记录很重要
                // 因为我们现在有一个约束违反
                [database removeApp:app];
                
                break;
            }
        }
        
        // 继续循环，直到列表不再被改变
    } while (appWasRemoved);
    
    host.appList = newHostAppList;
    [database updateAppsForExistingHost:host];
    
    // 这个主机可能有资格使用快捷方式，现在应用程序列表已被填充
    [self updateHostShortcuts];
}

- (void)showHostSelectionView {
    [_appManager stopRetrieving];
    _showHiddenApps = NO;
    _selectedHost = nil;
    _sortedAppList = nil;

    [self.collectionView reloadData];
    [self.view addSubview:self.hostScrollView];
}

// 现在更新盒子图像缓存，这样我们就不用做了，在主线程上处理
- (void)receivedAssetForApp:(TemporaryApp*)app {
    [self updateBoxArtCacheForApp:app];
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.collectionView reloadData];
    });
}

- (void)displayDnsFailedDialog {
    UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"网络错误" message:@"解析主机失败." preferredStyle:UIAlertControllerStyleAlert];
    [Utils addHelpOptionToDialog:alert];
    [alert addAction:[UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil]];
    [[self activeViewController] presentViewController:alert animated:YES completion:nil];
}


//MARK: - 点击PC
- (void)hostClicked:(TemporaryHost *)host view:(UIView *)view {
    if (host.state != StateOnline && view != nil) {
        [self hostLongClicked:host view:view];
        return;
    }
    
    Log(LOG_I, @"点击主机: %@", host.name);
    
    _selectedHost = host;
    [self disableNavigation];
    
    // 如果我们在线，配对，并且有一个缓存的应用列表，直接跳过
    if (host.state == StateOnline
        && host.pairState == PairStatePaired
        && host.appList.count > 0
        && view != nil) {
        [self alreadyPaired];
        return;
    }
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 等待PC的状态可知
        while (host.state == StateUnknown) {
            sleep(1);
        }
        
        // Don't bother polling if the server is already offline
        if (host.state == StateOffline) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self showHostSelectionView];
            });
            return;
        }
        
        HttpManager* hMan = [[HttpManager alloc] initWithHost:host];
        ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
        
        // 在处理serverinfo请求时，停止更新这个设备
        [self.discoveryMgr pauseDiscoveryForHost:host];
        
        [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp
                                                           withUrlRequest:[hMan newServerInfoRequest:false]
                                                            fallbackError:401
                                                          fallbackRequest:[hMan newHttpServerInfoRequest]]];
        [self.discoveryMgr resumeDiscoveryForHost:host];
        
        if (![serverInfoResp isStatusOk]) {
            Log(LOG_I, @"Failed to get server info: %@", serverInfoResp.statusMessage);
            dispatch_async(dispatch_get_main_queue(), ^{
                if (host != self->_selectedHost) {
                    return;
                }
                
                UIAlertController* applistAlert = [UIAlertController alertControllerWithTitle:@"连接失败"
                                                                                      message:serverInfoResp.statusMessage
                                                                               preferredStyle:UIAlertControllerStyleAlert];
                [Utils addHelpOptionToDialog:applistAlert];
                [applistAlert addAction:[UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil]];
                
                // 只显示一个警告，如果这是一个真实的结果
                // 用户动作，而不是被动地再次进入前台
                [self showHostSelectionView];
                
                if (view != nil) {
                    [[self activeViewController] presentViewController:applistAlert animated:YES completion:nil];
                }
                
                host.state = StateOffline;
            });
        } else {
            // 用这些数据更新主机对象
            [serverInfoResp populateHost:host];

            if (host.pairState == PairStatePaired) {
                Log(LOG_I, @"已经配对");
                [self alreadyPaired];
            }else if (view != nil) {               // 只有当这是明确的用户操作的结果时才对
                Log(LOG_I, @"尝试配对...");
                
                // 在配对时轮询服务器会导致服务器出错
                [self.discoveryMgr stopDiscoveryBlocking];
                
                // 配对管理，用回调更新
                PairManager* pMan = [[PairManager alloc] initWithManager:hMan isSunshine:self.isSunshine clientCert:self->_clientCert callback:self];
                [self->_opQueue addOperation:pMan];
            }else {
                // 不是用户操作，所以只是返回主机屏幕，显示游戏列表
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self showHostSelectionView];
                });
            }
        }
    });
    
}

- (UIViewController*)activeViewController {
    UIViewController *topController = [UIApplication sharedApplication].delegate.window.rootViewController;
    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }
    return topController;
}

// 长按设备
- (void)hostLongClicked:(TemporaryHost *)host view:(UIView *)view {
    Log(LOG_I, @"Long clicked host: %@", host.name);
}


//MARK: - 开机
/// 开机
/// - Parameters:
///   - ipAddress: ipAddress description
///   - vnName: 设备名字
///   - isSunshine: 是否是Sunshine
///   - completion: completion description
- (void)powerOn:(NSString *)ipAddress vnName:(NSString *)vnName isSunshine:(BOOL)isSunshine completion:(void (^)(BOOL success, NSString *msg))completion {
    NSLog(@"添加的PC 地址：%@, vnName：%@， isSunshine：%d", ipAddress, vnName, isSunshine);
    self.ipAddress = ipAddress;
    self.vnName = vnName;
    self.isSunshine = isSunshine;
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        [self.discoveryMgr discoverHost:ipAddress withCallback:^(TemporaryHost* host, NSString* error) {
            if (error) {
                if (completion != nil) {
                    completion(NO, error);
                }
                return;
            }
            
            // 找到了Host
            if (host != nil) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    @synchronized(self.hostList) {
                        [self.hostList addObject:host];
                    }
                    
                    NSLog(@"hostList = %@", self.hostList);
                    // 更新Host（并不是很重要的一步）
                    [self updateHosts];
                    
                    if (completion != nil) {
                        completion(YES, @"添加电脑成功");
                    }
                });
            } else {
                if (completion != nil) {
                    completion(NO, @"开机失败，Host 为空");
                }
            }
        }];
    });
}

//MARK: - 准备与PC串流
- (void)prepareToStreamApp:(TemporaryApp *)app {
    _streamConfig = [[StreamConfiguration alloc] init];
    _streamConfig.host = app.host.activeAddress;
    _streamConfig.httpsPort = app.host.httpsPort;
    _streamConfig.appID = app.id;
    _streamConfig.appName = app.name;
    _streamConfig.serverCert = app.host.serverCert;
    
    DataManager* dataMan = [[DataManager alloc] init];
    
    TemporarySettings* streamSettings = [dataMan getSettings];
    
    // 帧率
    _streamConfig.frameRate = 30;
    // 分辨率
    _streamConfig.width = 1920;
    _streamConfig.height = 1080;

    _streamConfig.bitRate = [streamSettings.bitrate intValue];
    _streamConfig.optimizeGameSettings = streamSettings.optimizeGames;
    _streamConfig.playAudioOnPC = streamSettings.playAudioOnPC;
    _streamConfig.allowHevc = streamSettings.useHevc;
    _streamConfig.useFramePacing = streamSettings.useFramePacing;
    _streamConfig.swapABXYButtons = streamSettings.swapABXYButtons;
    
    // multiController must be set before calling getConnectedGamepadMask
    _streamConfig.multiController = streamSettings.multiController;
    _streamConfig.gamepadMask = [ControllerSupport getConnectedGamepadMask:_streamConfig];
    
    // Probe for supported channel configurations
    int physicalOutputChannels = (int)[AVAudioSession sharedInstance].maximumOutputNumberOfChannels;
    Log(LOG_I, @"音频设备支持%d 渠道", physicalOutputChannels);
    
    int numberOfChannels = MIN([streamSettings.audioConfig intValue], physicalOutputChannels);
    Log(LOG_I, @"选定的音频通道数%d", numberOfChannels);
    if (numberOfChannels >= 8) {
        _streamConfig.audioConfiguration = AUDIO_CONFIGURATION_71_SURROUND;
    }else if (numberOfChannels >= 6) {
        _streamConfig.audioConfiguration = AUDIO_CONFIGURATION_51_SURROUND;
    }else {
        _streamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO;
    }
    
    // HDR需要HDR10显示和HEVC Main10解码器在客户端
    // 它还需要服务器上的HEVC Main10编码器(GTX 1000+)。
    if (@available(iOS 11.3, tvOS 11.2, *)) {
        _streamConfig.enableHdr =
        (app.host.serverCodecModeSupport & 0x200) != 0 && // HEVC Main10 encoding on host PC GPU
        VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC) && // Decoder supported
        (AVPlayer.availableHDRModes & AVPlayerHDRModeHDR10) != 0 && // Display supported
        streamSettings.enableHdr; // User wants it enabled
    }
}

/// 长按游戏
/// - Parameters:
///   - app: 游戏
///   - view: view description
- (void)appLongClicked:(TemporaryApp *)app view:(UIView *)view {
   
}


/// 点击游戏
/// - Parameters:
///   - app: app description
///   - view: view description
- (void)appClicked:(TemporaryApp *)app view:(UIView *)view {
    Log(LOG_I, @"Clicked app: %@", app.name);
    
    [_appManager stopRetrieving];
    
    if ([self findRunningApp:app.host]) {
        // 如果有正在运行的应用，显示一个菜单
        [self appLongClicked:app view:view];
    } else {
        [self prepareToStreamApp:app];
        [self toStreamFrameVc];
    }
}

- (TemporaryApp*)findRunningApp:(TemporaryHost*)host {
    for (TemporaryApp* app in host.appList) {
        if ([app.id isEqualToString:host.currentGame]) {
            return app;
        }
    }
    return nil;
}

//MARK: - 到电脑详情页面
-(void)toStreamFrameVc {
    StreamFrameViewController *streamFrame = [StreamFrameViewController new];
    streamFrame.streamConfig = _streamConfig;
    [self.superController.navigationController pushViewController:streamFrame animated:YES];
}

- (void)adjustScrollViewForSafeArea:(UIScrollView*)view {
    if (@available(iOS 11.0, *)) {
        if (self.view.safeAreaInsets.left >= 20 || self.view.safeAreaInsets.right >= 20) {
            view.contentInset = UIEdgeInsetsMake(0, 20, 0, 20);
        }
    }
}

// Adjust the subviews for the safe area on the iPhone X.
- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    
    [self adjustScrollViewForSafeArea:self.collectionView];
    [self adjustScrollViewForSafeArea:self.hostScrollView];
}


// 页面加载
- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"设备列表";
    self.view.backgroundColor = [UIColor blackColor];
}

-(void)setOther {
    // Set up crypto
    [CryptoManager generateKeyPairUsingSSL];
    
    _uniqueId = [IdManager getUniqueId];
    _clientCert = [CryptoManager readCertFromFile];
    
    _opQueue = [[NSOperationQueue alloc] init];
    _boxArtCache = [[NSCache alloc] init];
    
    self.hostScrollView = [[ComputerScrollView alloc] init];
    self.hostScrollView.frame = self.view.bounds;
    [self.hostScrollView setShowsHorizontalScrollIndicator:NO];
    self.hostScrollView.delaysContentTouches = NO;
    
    UICollectionViewFlowLayout * flowLayout = [UICollectionViewFlowLayout new];
    flowLayout.itemSize = CGSizeMake(100, 150);
    flowLayout.minimumLineSpacing = 10;
    flowLayout.minimumInteritemSpacing = 20;
    
    self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
    self.collectionView.backgroundColor = UIColor.clearColor;
    self.collectionView.delegate = self;
    self.collectionView.dataSource = self;
    self.collectionView.delaysContentTouches = NO;
    self.collectionView.allowsMultipleSelection = NO;
    self.collectionView.multipleTouchEnabled = NO;
    [self.collectionView registerClass:UICollectionViewCell.class forCellWithReuseIdentifier:@"AppCell"];
    [self.view addSubview:self.collectionView];
    
    [self retrieveSavedHosts];
}

-(void)beginForegroundRefresh {
    if (!_background) {
        // 这将开启盒子图像缓存
        [self updateHosts];
        
        // ???: 首先重置状态，以便我们可以重新发现之前删除的主机
        // !!!: 不自动扫描
        [_discoveryMgr resetDiscoveryState];
        [_discoveryMgr startDiscovery];
        
        // 这将在选择配对主机时刷新应用程序
        if (_selectedHost != nil && _selectedHost.pairState == PairStatePaired) {
            [self hostClicked:_selectedHost view:nil];
        }
    }
}

-(void)handlePendingShortcutAction {
    //  检查我们是否有一个挂起的快捷操作
    AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    if (delegate.pcUuidToLoad != nil) {
        // Find the host it corresponds to
        TemporaryHost* matchingHost = nil;
        for (TemporaryHost* host in self.hostList) {
            if ([host.uuid isEqualToString:delegate.pcUuidToLoad]) {
                matchingHost = host;
                break;
            }
        }
        
        // 清除挂起的快捷操作
        delegate.pcUuidToLoad = nil;
        
        // Complete the request
        if (delegate.shortcutCompletionHandler != nil) {
            delegate.shortcutCompletionHandler(matchingHost != nil);
            delegate.shortcutCompletionHandler = nil;
        }
        
        if (matchingHost != nil && _selectedHost != matchingHost) {
            // Navigate to the host page
            [self hostClicked:matchingHost view:nil];
        }
    }
}

-(void)handleReturnToForeground {
    _background = NO;
    
    [self beginForegroundRefresh];
    
    // 返回前台时检查是否有挂起的快捷操作
    [self handlePendingShortcutAction];
}

-(void)handleEnterBackground {
    _background = YES;
    
    [_discoveryMgr stopDiscovery];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    
    // Hide 1px border line
    UIImage* fakeImage = [[UIImage alloc] init];
    [self.navigationController.navigationBar setShadowImage:fakeImage];
    [self.navigationController.navigationBar setBackgroundImage:fakeImage forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
    
    // Check for a pending shortcut action when appearing
    [self handlePendingShortcutAction];
    
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(handleReturnToForeground)
                                                 name: UIApplicationDidBecomeActiveNotification
                                               object: nil];
    
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(handleEnterBackground)
                                                 name: UIApplicationWillResignActiveNotification
                                               object: nil];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    [self beginForegroundRefresh];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    
    [_discoveryMgr stopDiscovery];
    [_boxArtCache removeAllObjects];
    
    // Remove our lifetime observers
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)retrieveSavedHosts {
    DataManager* dataMan = [[DataManager alloc] init];
    NSArray* hosts = [dataMan getHosts];
    @synchronized(self.hostList) {
        [self.hostList addObjectsFromArray:hosts];
        
        // Initialize the non-persistent host state
        for (TemporaryHost* host in self.hostList) {
            //            if (host.activeAddress == nil) {
            //                host.activeAddress = host.localAddress;
            //            }
            if (host.activeAddress == nil) {
                host.activeAddress = host.externalAddress;
            }
            if (host.activeAddress == nil) {
                host.activeAddress = host.address;
            }
            if (host.activeAddress == nil) {
                host.activeAddress = host.ipv6Address;
            }
        }
    }
}

- (void)updateAllHosts:(NSArray *)hosts {
    // 这里必须复制数组，在主线程调度发生之前它可以被修改
    NSArray* hostsCopy = [NSArray arrayWithArray:hosts];
    dispatch_async(dispatch_get_main_queue(), ^{
        Log(LOG_I, @"New host list:");
        for (TemporaryHost* host in hostsCopy) {
            Log(LOG_I, @"Host: \n{\n\t name:%@ \n\t address:%@ \n\t externalAddress:%@ \n\t ipv6Address:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n\t activeAddress:%@ \n}", host.name, host.address, host.externalAddress, host.ipv6Address, host.uuid, host.mac, host.pairState, host.state, host.activeAddress);
        }
        @synchronized(self.hostList) {
            [self.hostList removeAllObjects];
            [self.hostList addObjectsFromArray:hostsCopy];
        }
        [self updateHosts];
    });
}

- (void)updateHostShortcuts {
    NSMutableArray* quickActions = [[NSMutableArray alloc] init];
    
    @synchronized (self.hostList) {
        for (TemporaryHost* host in self.hostList) {
            // 如果我们还没有轮询Pair, Pair状态可能是未知的，但是应用程序列表
            // 计数将持续从配对的pc
            if ([host.appList count] > 0) {
                UIApplicationShortcutItem* shortcut = [[UIApplicationShortcutItem alloc]
                                                       initWithType:@"PC"
                                                       localizedTitle:host.name
                                                       localizedSubtitle:nil
                                                       icon:[UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypePlay]
                                                       userInfo:[NSDictionary dictionaryWithObject:host.uuid forKey:@"UUID"]];
                [quickActions addObject: shortcut];
            }
        }
    }
    
    [UIApplication sharedApplication].shortcutItems = quickActions;
}

//MARK: - 更新Host
- (void)updateHosts {
    Log(LOG_I, @"Updating hosts...");
    [[self.hostScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
    
    UIComputerView* addComp = [[UIComputerView alloc] initForAddWithCallback:self];
    UIComputerView* compView;
    float prevEdge = -1;
    @synchronized (self.hostList) {
        // Sort the host list in alphabetical order
        NSArray* sortedHostList = [[self.hostList allObjects] sortedArrayUsingSelector:@selector(compareName:)];
        for (TemporaryHost* comp in sortedHostList) {
            compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self];
            compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], self.hostScrollView.frame.size.height / 2);
            prevEdge = compView.frame.origin.x + compView.frame.size.width;
            [self.hostScrollView addSubview:compView];
            
            // Start jobs to decode the box art in advance
            for (TemporaryApp* app in comp.appList) {
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
                    [self updateBoxArtCacheForApp:app];
                });
            }
        }
    }
    
    prevEdge = [self getCompViewX:addComp addComp:addComp prevEdge:prevEdge];
    addComp.center = CGPointMake(prevEdge, self.hostScrollView.frame.size.height / 2);
    
    [self.hostScrollView addSubview:addComp];
    [self.hostScrollView setContentSize:CGSizeMake(prevEdge + addComp.frame.size.width, self.hostScrollView.frame.size.height)];
}

- (float)getCompViewX:(UIComputerView*)comp addComp:(UIComputerView*)addComp prevEdge:(float)prevEdge {
    float padding = addComp.frame.size.width / 2;
    if (prevEdge == -1) {
        return self.hostScrollView.frame.origin.x + comp.frame.size.width / 2 + padding;
    } else {
        return prevEdge + comp.frame.size.width / 2 + padding;
    }
}

// 这个函数强制立即解码UIImage，而不是比默认的导致滚动的延迟解码。
+ (UIImage*)loadBoxArtForCaching:(TemporaryApp*)app {
    UIImage* boxArt;
    
    NSData* imageData = [NSData dataWithContentsOfFile:[AppAssetManager boxArtPathForApp:app]];
    if (imageData == nil) {
        // No box art on disk
        return nil;
    }
    
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
    CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil);
    
    size_t width = CGImageGetWidth(cgImage);
    size_t height = CGImageGetHeight(cgImage);
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef imageContext =  CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace,
                                                       kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
    CGColorSpaceRelease(colorSpace);
    
    CGContextDrawImage(imageContext, CGRectMake(0, 0, width, height), cgImage);
    
    CGImageRef outputImage = CGBitmapContextCreateImage(imageContext);
    
    boxArt = [UIImage imageWithCGImage:outputImage];
    
    CGImageRelease(outputImage);
    CGContextRelease(imageContext);
    
    CGImageRelease(cgImage);
    CFRelease(source);
    
    return boxArt;
}

- (void)updateBoxArtCacheForApp:(TemporaryApp*)app {
    if ([_boxArtCache objectForKey:app] == nil) {
        UIImage* image = [MainFrameViewController loadBoxArtForCaching:app];
        if (image != nil) {
            // 如果图像存在，将其添加到缓存中
            [_boxArtCache setObject:image forKey:app];
        }
    }
}

- (void)updateAppsForHost:(TemporaryHost*)host {
    if (host != _selectedHost) {
        Log(LOG_I, @"Mismatched host during app update");
        return;
    }
    
    _sortedAppList = [host.appList allObjects];
    _sortedAppList = [_sortedAppList sortedArrayUsingSelector:@selector(compareName:)];
    NSMutableArray <TemporaryApp *>* visibleAppList = [NSMutableArray array];
    
    if (!_showHiddenApps) {
        for (TemporaryApp* app in _sortedAppList) {
            if (!app.hidden) {
                [visibleAppList addObject:app];
            }
        }
        _sortedAppList = visibleAppList;
    }
    
    [self.hostScrollView removeFromSuperview];
    [self.collectionView reloadData];
    
    // 模拟点击
    [visibleAppList enumerateObjectsUsingBlock:^(TemporaryApp * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj.name isEqualToString:@"Desktop"] || [obj.name isEqualToString:@"mstsc"]) {
            // 延迟
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self appClicked:obj view:[UIAppView new]];
            });
            *stop = YES;
        }
    }];
}


//MARK: - UICollectionViewCellDataSource

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath];
    
    TemporaryApp* app = _sortedAppList[indexPath.row];
    UIAppView* appView = [[UIAppView alloc] initWithApp:app cache:_boxArtCache andCallback:self];
    
    if (appView.bounds.size.width > 10.0) {
        CGFloat scale = cell.bounds.size.width / appView.bounds.size.width;
        [appView setCenter:CGPointMake(appView.bounds.size.width / 2 * scale, appView.bounds.size.height / 2 * scale)];
        appView.transform = CGAffineTransformMakeScale(scale, scale);
    }
    
    [cell.subviews.firstObject removeFromSuperview]; // Remove a view that was previously added
    [cell addSubview:appView];
    
    // Shadow
    UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:cell.bounds];
    cell.layer.masksToBounds = NO;
    cell.layer.shadowColor = [UIColor blackColor].CGColor;
    cell.layer.shadowOffset = CGSizeMake(1.0f, 5.0f);
    cell.layer.shadowPath = shadowPath.CGPath;
    cell.layer.borderWidth = 1;
    cell.layer.borderColor = [[UIColor colorWithRed:0 green:0 blue:0 alpha:0.3f] CGColor];
    cell.exclusiveTouch = YES;
    
    return cell;
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    if (_selectedHost != nil && _sortedAppList != nil) {
        return _sortedAppList.count;
    }else {
        return 0;
    }
}

- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    
}

// lazy load
-(DiscoveryManager *)discoveryMgr {
    if (!_discoveryMgr) {
        _discoveryMgr = [[DiscoveryManager alloc] initWithHosts:[self.hostList allObjects] andCallback:self];
    }
    return _discoveryMgr;
}

- (AppAssetManager *)appManager {
    if (!_appManager) {
        _appManager = [[AppAssetManager alloc] initWithCallback:self];
    }
    return  _appManager;
}

- (NSMutableSet <TemporaryHost *>*)hostList {
    if (!_hostList) {
        _hostList = [NSMutableSet new];
    }
    return _hostList;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    [_boxArtCache removeAllObjects];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}

// 自动旋转
- (BOOL)shouldAutorotate {
    return YES;
}

- (void)disableNavigation {
    self.navigationController.navigationBar.topItem.rightBarButtonItem.enabled = NO;
    self.navigationController.navigationBar.topItem.leftBarButtonItem.enabled = NO;
}

- (void)enableNavigation {
    self.navigationController.navigationBar.topItem.rightBarButtonItem.enabled = YES;
    self.navigationController.navigationBar.topItem.leftBarButtonItem.enabled = YES;
}

- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator {
    if (context.nextFocusedView != nil) {
        [context.nextFocusedView setAlpha:0.8];
    }
    [context.previouslyFocusedView setAlpha:1.0];
}

@end
